#ifndef __BB_DATA_STREAM_H__
#define __BB_DATA_STREAM_H__

#include <any>
#include <unordered_map>

#include "../node/node_info.h"
#include "exception/exception.h"

namespace bb::data {

class DataStream {
  private:
    bool        initialized_{false};
    std::string name_;
    std::any    value_;
    std::any    default_;

  public:
    DataStream(std::string name, std::any value) : initialized_(true), name_(name), value_(value), default_(value) {}
    DataStream(std::string name, std::any value, std::any default_value)
            : initialized_(true), name_(name), value_(value), default_(default_value) {}
    void operator=(const std::any& value) {
        initialized_ = true;
        value_       = value;
    }
    void operator=(const DataStream& data_stream) {
        initialized_ = true;
        value_       = data_stream.value_;
        default_     = data_stream.default_;
    }
    void SetValue(const std::any& value) {
        initialized_ = true;
        value_       = value;
    }
    void SetDefault(const std::any& default_value) {
        initialized_ = true;
        default_     = default_value;
    }
    void SetValue(const std::any& value, const std::any& default_value) {
        initialized_ = true;
        value_       = value;
        default_     = default_value;
    }

    template <typename _AnyType>
    auto Value() -> _AnyType {
        if (initialized_) try {
                return std::any_cast<_AnyType>(value_);
            } catch (const std::bad_any_cast&) {
                throw exception::RuntimeError("DataStream [", name_,
                                              "]: bad any_cast!"
                                              "this data stream storaged type is inconsistent with the target type!");
            }
        else
            throw exception::LogicError("DataStream [", name_,
                                        "]: data stream not initialized, it's value is unreliable!"
                                        "initialize it by using operator= or SetValue(value)");
    }

    template <typename _AnyType>
    auto DefaultValue() -> _AnyType {
        if (initialized_) try {
                return std::any_cast<_AnyType>(default_);
            } catch (const std::bad_any_cast&) {
                throw exception::RuntimeError("DataStream [", name_,
                                              "]: bad any_cast!"
                                              "this data stream storaged type is inconsistent with the target type!");
            }
        else
            throw exception::LogicError("DataStream [", name_,
                                        "]: data stream not initialized, it's default value is unreliable!"
                                        "initialize it by using operator= or SetValue(value)");
    }

    auto ToBool() -> bool { return Value<bool>(); }
    auto ToStatus() -> node::NodeStatus { return Value<node::NodeStatus>(); }
    auto DefaultBool() -> bool { return DefaultValue<bool>(); }
    auto DefaultStatus() -> node::NodeStatus { return DefaultValue<node::NodeStatus>(); }

    void Reset() { initialized_ = false; }
    void ResetToDefault() { value_ = default_; }
};

} // namespace bb::data

#endif // __BB_DATA_STREAM_H__